package com.db.stockexchange.client;

import java.io.IOException;
import java.net.InetAddress;

import com.db.stockexchange.common.OrderSide;
import com.db.stockexchange.common.OrderStatus;
import com.db.stockexchange.common.OrderType;
import com.db.stockexchange.common.messages.FIXMessage;
import com.db.stockexchange.common.messages.client.*;
import com.db.stockexchange.common.messages.server.*;

public class MessageHandler {
	ClientEngine engine;
	Connection connection;
	String clientID;
	
	public MessageHandler(ClientEngine engine, String clientID, InetAddress address, int port) throws IOException {
		this.engine = engine;
		connection = new Connection(address, port, this);
		new Thread(connection).start();
		this.clientID = clientID;
		sendLogin();
	}
	
	public void processMessage(FIXMessage message) {
		switch (message.getType()) {
		case LOGON:
			break;
		case EXEC_REPORT:
			exec_report((ExecutionReportMessage)message);
			break;
		case REJECT:
			reject((RejectedMessage)message);
			break;
		default:
			break;
		}
	}
	
	private void reject(RejectedMessage message) {
		engine.reject(message.getReasonDetail());		
	}

	private void exec_report(ExecutionReportMessage message) {
		switch(message.getOrderStatus()) {
		case NEW:
			ack((AckMessage)message);
			break;
		case REJECTED:
			rejected((ExecutionRejectMessage)message);
			break;
		case FILLED:
		case PARTIALLY_FILLED:
			filled((FilledMessage)message);
			break;
		case CANCELLED:
			break;
		}
		
	}

	private void ack(AckMessage message) {
		engine.ack(message.getOrderID());		
	}

	private void filled(FilledMessage message) {
		engine.fill(message.getOrderID(), message.getCumQuantity(), message.getLeavesQuantity(), getStockState(message.getOrderStatus()));
	}

	private void rejected(ExecutionRejectMessage message) {
		engine.reject(message.getOrderID(), message.getDetail());
		
	}

	public void sendLogin() {
		connection.sendMessage(new LogonMessage(clientID));
	}
	
	public void sendLogout() {
		connection.sendMessage(new LogoutMessage(clientID));
	}
	public void sendNewOrder(Stock stock) {
		/*FIXMessage response = connection.sendSynchronousMessage(new NewOrderMessage(clientID, stock.getId(), stock.getName(), getOrderSide(stock), stock.getShareNumber(), getOrderType(stock), stock.getPrice()));
		if (response != null) {
			processMessage(response);
		}*/
		connection.sendMessage(new NewOrderMessage(clientID, stock.getId(), stock.getName(), getOrderSide(stock), stock.getShareNumber(), getOrderType(stock), stock.getPrice()));
	}

	private OrderSide getOrderSide(Stock stock) {
		switch (stock.getOperation()) {
		case BUY:
			return OrderSide.BUY;
		case SELL:
			return OrderSide.SELL;
		}
		return null;
	}

	private OrderType getOrderType(Stock stock) {
		if (stock.isUseBestMarketPrice())
			return OrderType.MARKET;
		else
			return OrderType.LIMIT;
	}

	private StockState getStockState(OrderStatus orderStatus) {
		StockState state = null;
		switch(orderStatus) {
		case NEW: state = StockState.NEW;break;
		case PARTIALLY_FILLED: state = StockState.PARTIALLY_FILLED;break;
		case FILLED: state = StockState.FILLED;break;
		case CANCELLED: state = StockState.CANCELLED;break;
		case REJECTED: state = StockState.REJECTED;break;
		}
		return state;
	}
	
	public void close() {
		sendLogout();
		connection.close();
	}
}
